package orbito.util;

import java.awt.geom.AffineTransform;

public class Vec2 {
	public double x, y;
	
	public Vec2() {
		this(0.0, 0.0);
	}
	
	public Vec2(Vec2 other) {
		this(other.x, other.y);
	}
	
	public Vec2(double x, double y) {
		this.x = x;
		this.y = y;
	}
	
	public Vec2 add(Vec2 other) {
		return new Vec2(this.x + other.x, this.y + other.y);
	}
	
	public Vec2 iadd(Vec2 other) {
		this.x += other.x;
		this.y += other.y;
		return this;
	}
	
	public Vec2 sub(Vec2 other) {
		return new Vec2(this.x - other.x, this.y - other.y);
	}
	
	public Vec2 isub(Vec2 other) {
		this.x -= other.x;
		this.y -= other.y;
		return this;
	}
	
	public Vec2 mul(double k) {
		return new Vec2(x * k, y * k);
	}
	
	public Vec2 imul(double k) {
		x *= k;
		y *= k;
		return this;
	}
	
	public Vec2 div(double k) {
		double ik = 1 / k;
		return new Vec2(x * ik, y * ik);
	}
	
	public Vec2 idiv(double k) {
		double ik = 1 / k;
		x *= ik;
		y *= ik;
		return this;
	}
	
	public Vec2 negate() {
		return new Vec2(-x, -y);
	}
	
	public Vec2 inegate() {
		x = -x;
		y = -y;
		return this;
	}
	
	public Vec2 unit() {
		double il = 1 / length();
		return new Vec2(x * il, y * il);
	}
	
	public Vec2 iunit() {
		double il = 1 / length();
		x *= il;
		y *= il;
		return this;
	}
	
	public Vec2 normal() {
		return new Vec2(-y, x);
	}
	
	public Vec2 inormal() {
		double tmp = x;
		x = -y;
		y = tmp;
		return this;
	}
	
	public Vec2 zeroize() {
		x = 0.0;
		y = 0.0;
		return this;
	}
	
	public double length() {
		return Math.sqrt(x * x + y * y);
	}
	
	public double lengthSquared() {
		return x * x + y * y;
	}
	
	/**
	 * Gets the rotated vector with the given angular offset.
	 * 
	 * For 2-dimensional vectors, this is stipulated to the equivalent 
	 * of rotating a 3-dimensional vector about the z-axis.
	 * 
	 * @param offset The angular offset, in radians.
	 * @return The rotated vector.
	 */
	public Vec2 rotate(double offset) {
		double angle = Math.atan2(y, x) + offset;
		double len = length();
		return new Vec2(len * Math.cos(angle), len * Math.sin(angle));
	}
	
	/**
	 * Tranforms the vector by the affine transform tr.
	 * 
	 * @param tr The affine transform.
	 * @return The transformed vector.
	 */
	public Vec2 transform(AffineTransform tr) {
		double[] arr = new double[] { x, y };
		tr.transform(arr, 0, arr, 0, 1);
		return new Vec2(arr[0], arr[1]);
	}
	
	/**
	 * Dot product of two vectors.
	 * Source: http://en.wikipedia.org/wiki/Dot_product
	 * 
	 * @param a
	 * @param b
	 * @return The dot product.
	 */
	public static double dot(Vec2 a, Vec2 b) {
		return a.x * b.x + a.y * b.y;
	}
	
	/**
	 * Cross product of two vectors.
	 * Source: http://en.wikipedia.org/wiki/Cross_product
	 * 
	 * For 2-dimensional vectors, this is stipulated to the length of 
	 * the z-axis of the 3-dimension equivalent.
	 * 
	 * @param a
	 * @param b
	 * @return The cross product.
	 */
	public static double cross(Vec2 a, Vec2 b) {
		return a.x * b.y + a.y * b.x;
	}
	
	/**
	 * Relative angle between two vectors.
	 * 
	 * @param a
	 * @param b
	 * @return Relative angle between two vectors, in radians.
	 */
	public static double getRelativeAngle(Vec2 a, Vec2 b) {
		return Math.acos(Vec2.dot(a.unit(), b.unit()));
	}
	
	/**
	 * Linear interpolatation between two vectors.
	 * Source: http://en.wikipedia.org/wiki/Linear_interpolation
	 * 
	 * @param a
	 * @param b
	 * @param factor The factor, typically in [0,1].
	 * @return The linearly interpolated vector.
	 */
	public static Vec2 lerp(Vec2 a, Vec2 b, double factor) {
		return new Vec2(
				a.x + (b.x - a.x) * factor,
				a.y + (b.y - a.y) * factor);
	}
	
	public String toString() {
		return String.format("Vec2(%.2f, %.2f)", x, y);
	}
}
